package org.zjt.mock.demo.mock;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.*;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
import org.zjt.mock.demo.mock.annotation.CustomizedComponent;
import org.zjt.mock.demo.mock.bean.ComponentBean;
import org.zjt.mock.demo.mock.domain.User;

import java.beans.PropertyEditorSupport;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Iterator;

import static org.springframework.beans.factory.config.BeanDefinition.SCOPE_SINGLETON;

@SpringBootApplication
@Slf4j
@Getter
@Setter
@ServletComponentScan
public class MockDemoApplication {

	private User user;

	private Date date;

	public static void main(String[] args) {
		CustomizedClassPathXmlApplicationContext applicationContext = new CustomizedClassPathXmlApplicationContext();

		applicationContext.refresh();

		Object obj = applicationContext.getBean("zhang");
		log.info(obj.toString());

        ComponentBean bean = applicationContext.getBean(ComponentBean.class);
        log.info(bean.toString());

        //SpringApplication.run(MockDemoApplication.class, args);
	}


	public static class CustomizedClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{


	    private final BeanFactoryPostProcessor beanFactoryPostProcessor;


        public CustomizedClassPathXmlApplicationContext() {

            /**
             * 增加一个beanFactory 的处理方法
             */
            this.beanFactoryPostProcessor = beanFactory -> {
                Iterator<String> beanNamesIterator = beanFactory.getBeanNamesIterator();
                for (;beanNamesIterator.hasNext();){
                    String next = beanNamesIterator.next();
                    log.info("beanName :{}",next);
                }
            };

            /**
             * spring application 监听器
             */
            this.addApplicationListener(event -> log.info(String.valueOf(event)));

            this.addBeanFactoryPostProcessor(beanFactoryPostProcessor);
        }

        /**
         * 加载 Bean Definitions
         * @param beanFactory
         * @throws BeansException
         * @throws IOException
         */
		@Override
		protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {

			super.loadBeanDefinitions(beanFactory);

			BeanDefinition beanDefinition = new RootBeanDefinition();
			beanDefinition.setBeanClassName(MockDemoApplication.class.getName());
			beanDefinition.setLazyInit(Boolean.TRUE);
			beanDefinition.setScope(SCOPE_SINGLETON);
			beanDefinition.setPrimary(Boolean.TRUE);

			/** 增加属性 user 设置**/
			beanDefinition.getPropertyValues().add("user","ZhangJuntao,24");
			beanDefinition.getPropertyValues().add("date","2018-08-12 10:22:03");

			/** DI: 依赖注入hshs的对象 **/
			// beanDefinition.setDependsOn("hshsh");

			beanDefinition.setAutowireCandidate(Boolean.FALSE);
			BeanDefinitionHolder bdHolder = new BeanDefinitionHolder(beanDefinition,"zhang");


			/** {@link BeanDefinitionRegistry }**/
			BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, beanFactory);


			/** 扫描注解的bean {@link CustomizedComponent }**/
            ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(beanFactory);
            classPathBeanDefinitionScanner.addIncludeFilter(new AnnotationTypeFilter(CustomizedComponent.class));
            classPathBeanDefinitionScanner.scan("org.zjt.mock.demo.mock.bean");
        }


		/**
		 * 当所有的Bean Definition 都初始化结束,Bean 没有被初始化。可以用来更改 applicationContext 中的BeanFactory。
		 * {@link PropertyEditorSupport}
		 *
		 * 例如：可以新增 BeanPostProcessors
		 *
		 * @param beanFactory the bean factory used by the application context
		 */
		@Override
		protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

            /**
             * 设置Bean post processor
             */
			beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
				@Override
				public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
					log.info("-------------postProcessBeforeInitialization--------------");
					return bean;
				}

				@Override
				public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
					log.info("-------------postProcessAfterInitialization--------------");
					return bean;
				}
			});

			beanFactory.addEmbeddedValueResolver(strVal -> {
                log.info("------------strVal:{}-----------",strVal);
                return strVal;
            });


            /**
             * 设置 bean Properties 的读取方式
             */
			beanFactory.addPropertyEditorRegistrar(registry -> {
                registry.registerCustomEditor(User.class,new UserPropertyEditorSupport());
                registry.registerCustomEditor(Date.class,new DatePropertyEditorSupport());
            });
		}
	}


    /**
     * {@link PropertyEditorSupport}
     */
	public static class UserPropertyEditorSupport extends PropertyEditorSupport{

	    @Override
        public void setAsText(String text) throws java.lang.IllegalArgumentException {
            String[] data = text.split(",");
            User user = new User();
            user.setName(data[0]);
            user.setAge(Integer.parseInt(data[1]));
            this.setValue(user);
        }
    }


    /**
     * 设置日期的property set 读取
     */
    public static class DatePropertyEditorSupport extends PropertyEditorSupport{

    	private final static DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    	private final static ZoneId ZONE_ID = ZoneId.systemDefault();

        @Override
        public void setAsText(String text) throws java.lang.IllegalArgumentException {
            long epochMilli = LocalDateTime.parse(text,DATE_TIME_FORMATTER).atZone(ZONE_ID).toInstant().toEpochMilli();
            this.setValue(new Date(epochMilli));
        }
    }
}
